#include "stdafx.h"
#include "ProjectItem.h"
#include <LitCore.h>
#include <LitSceneManager.h>

ProjectNode::ProjectNode( ItemPtr item, Type type, Lit::MovablePtr mov ) 
	: mItem( item ), mType( type ), mMovable( mov )
{}
ProjectNode::~ProjectNode( )
{
}
	
void							ProjectNode::setMovable( Lit::MovablePtr mov )	{ mMovable=mov; }
Lit::MovablePtr					ProjectNode::movable() const					{ return mMovable; }
bool							ProjectNode::isType( Type t ) const				{ return mType == t; }
ProjectNode::Type				ProjectNode::type( ) const						{ return mType; }
std::string						ProjectNode::typeStr() const					{ return trProjectNodeType( mType ); }
ProjectNode::ItemPtr			ProjectNode::item() const						{ return mItem; }
std::string						ProjectNode::getName() const						{ return mItem->text(0).toAscii().data(); }

void							ProjectNode::unlinkItem( )
{
	if( mItem ) delete mItem;
	mItem = NULL;
}

ProjectStructure::ProjectStructure( const std::string &projectName, TreeType * tree )
	: mTree( tree )
{
	setup( projectName, tree );
}
ProjectStructure::ProjectStructure( ) : mTree(NULL)
{
}
ProjectStructure::ProjectStructure( const ProjectStructure& rk )
{
	mRoot = rk.mRoot;
	mNodes = rk.mNodes;
	mTree = rk.mTree;
}
ProjectStructure::~ProjectStructure( ){ 
	destroyNodes(); 
}

	
ProjectStructure::NodeMap& ProjectStructure::nodes(){ return mNodes; }
const ProjectStructure::NodeMap& ProjectStructure::nodes() const{ return mNodes; }

void ProjectStructure::setup( const std::string &projectName, TreeType * tree  )
{
	mTree = tree;
	if( !mRoot )
	{
		mRoot = createTopLevelNode( projectName );
		mEntities = createFolder( "Entities", mRoot );
		mLights = createFolder( "Lights", mRoot );
		mSounds = createFolder( "Sounds", mRoot );
	}
}
ProjectNodePtr ProjectStructure::rootNode() const{ return mRoot; }
ProjectNodePtr ProjectStructure::entitiesNode() const{ return mEntities; }
ProjectNodePtr ProjectStructure::lightsNode() const{ return mLights; }
ProjectNodePtr ProjectStructure::soundsNode() const{ return mSounds; }

ProjectNodePtr ProjectStructure::createTopLevelNode( const std::string &name )
{
	if( hasNode( fromItemName(name) ) )
		throw Lit::ItemDuplicate( name, "ProjectStructure", EXC_LOC );

	ProjectNodePtr ptr( new ProjectNode( new QTreeWidgetItem(mTree, QStringList(QString(name.c_str()))), PNT_SCENE ) );
	mNodes[name] = ptr;
	ptr->item()->setExpanded( true );
	return ptr;
}
ProjectNodePtr ProjectStructure::createFolder( const std::string &name, ProjectNodePtr parentNode )
{
	return createNode( name, PNT_FOLDER, Lit::MovablePtr(), parentNode );
}
ProjectNodePtr ProjectStructure::createNode( const std::string &name, Node::Type type, Lit::MovablePtr mov, ProjectNodePtr parentNode )
{
	if( hasNode( fromItemName(name) ) )
		throw Lit::ItemDuplicate( name, "ProjectStructure", EXC_LOC );

	QTreeWidgetItem * parent = (parentNode?parentNode->item():mRoot->item());
	ProjectNodePtr ptr( new ProjectNode( new QTreeWidgetItem(parent, QStringList(QString(name.c_str()))), type, mov ) );
	mNodes[name] = ptr;
	ptr->item()->setExpanded( true );
	return ptr;
}
void ProjectStructure::_destroyNode( NodePtr & node, bool unlink )
{
	if( !node ) return;
	std::string n = node->getName();
	Lit::SceneManagerPtr mgr = Lit::Root::Instance().component<Lit::SceneManager>(Lit::COM_SCENEMANAGER);

	switch( node->type() )
	{
	case PNT_ENTITY:
		mgr->removeEntity( n );
		break;
	case PNT_LIGHT:
	{
		if( node->movable()->hasData( "EntityBuddy" ) )
			Lit::Root::SceneManager()->removeEntity( node->movable()->getData("EntityBuddy", std::string()) );
		mgr->removeLight( n );
		break;
	}
	case PNT_SOUND:
		break;
	case PNT_PLANE:
		mgr->removePlane( n );
		break;
	case PNT_UNKNOWN:
		break;
	};
	if( node->item() && unlink )
	{
		mTree->blockSignals(true);
		node->unlinkItem();
		mTree->blockSignals(false);
	}
	node.destroy();
}
void ProjectStructure::destroyNodes( )
{
	Lit::Root::SceneManager()->clearSelection();
	mTree->blockSignals( true );
	for( NodeMap::iterator i = mNodes.begin(); i != mNodes.end(); i++ ) _destroyNode( i->second, false );
	mTree->clear();
	mNodes.clear();
	mRoot = NULL;
	mEntities = NULL;
	mLights = NULL;
	mSounds = NULL;
	mTree->blockSignals( false );
}

ProjectStructure::Node::ItemPtr ProjectStructure::fromItemName( const std::string &name )
{
	for( NodeMap::const_iterator i = mNodes.begin(); i != mNodes.end(); i++ ) 
		if( i->second->item() && (i->second->item()->text(0) == name.c_str()) ) 
			return i->second->item();
	return NULL;
}
ProjectStructure::Node::ItemPtr ProjectStructure::fromMovable( Lit::MovablePtr mov )
{
	for( NodeMap::const_iterator i = mNodes.begin(); i != mNodes.end(); i++ )
		if( i->second->movable() && i->second->movable() == mov ) 
			return i->second->item();
	return NULL;
}
bool ProjectStructure::hasNode( Node::ItemPtr n ) const
{
	for( NodeMap::const_iterator i = mNodes.begin(); i != mNodes.end(); i++ ) if( i->second->item() == n ) return true;
	return false;
}
	
ProjectStructure::NodePtr ProjectStructure::findNode( ProjectStructure::Node::ItemPtr n ) const
{
	for( NodeMap::const_iterator i = mNodes.begin(); i != mNodes.end(); i++ ) if( i->second->item() == n ) return i->second;
	return NULL;
}

ProjectStructure::NodePtr ProjectStructure::getNode( Node::ItemPtr n ) const
{
	for( NodeMap::const_iterator i = mNodes.begin(); i != mNodes.end(); i++ ) if( i->second->item() == n ) return i->second;
	throw Lit::ItemMissing( n->text(0).toAscii().data(), "ProjectStructure", EXC_LOC );
	return NULL;
}

void ProjectStructure::destroyNode( Node::ItemPtr n )
{
	for( NodeMap::iterator i = mNodes.begin(); i != mNodes.end(); i++ ) if( i->second->item() == n ){ _destroyNode( i->second, true ); mNodes.erase( i ); return; }
	throw Lit::ItemMissing( n->text(0).toAscii().data(), "ProjectStructure", EXC_LOC );
}

void ProjectStructure::eraseNode( Node::ItemPtr n )
{
	for( NodeMap::iterator i = mNodes.begin(); i != mNodes.end(); i++ ) if( i->second->item() == n ){ mNodes.erase( i ); return; }
	throw Lit::ItemMissing( n->text(0).toAscii().data(), "ProjectStructure", EXC_LOC );
}